package net.info.store;

import android.content.Context;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.snappydb.DB;
import com.snappydb.DBFactory;

public class SnappyStore implements KeyValueStore {

    private static String EXPIRE_KEY = "_expire:%s";

    private String name;
    private long expire;
    private DB db;
    private Context context;

    public SnappyStore(Context context, String name) {
        this(context, name, -1);
    }

    public SnappyStore(Context context, String name, long expire) {
        this.name = name;
        this.expire = expire;
        this.context = context;
        try {
            db = DBFactory.open(context, name);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public long getDefaultExpire() {
        return expire;
    }

    public void setDefaultExpire(long ms) {
        expire = ms;
    }

    public boolean hasKey(String k) {
        try {
            return db.exists(k);
        } catch (Exception e) {
        }
        return false;
    }

    public void del(String k) {
        try {
            db.del(k);
        } catch (Exception e) {
        }
    }

    public void cleanup() {
    }

    public void close() {
        try {
            db.close();
        } catch (Exception e) {
        }
    }

    public void set(String k, boolean v) {
        try {
            db.putBoolean(k, v);
            if (expire > 0)
                db.putLong(String.format(EXPIRE_KEY, k), System.currentTimeMillis() + expire);
        } catch (Exception e) {
        }
    }

    public void set(String k, int v) {
        try {
            db.putInt(k, v);
            if (expire > 0)
                db.putLong(String.format(EXPIRE_KEY, k), System.currentTimeMillis() + expire);
        } catch (Exception e) {
        }
    }

    public void set(String k, long v) {
        try {
            db.putLong(k, v);
            if (expire > 0)
                db.putLong(String.format(EXPIRE_KEY, k), System.currentTimeMillis() + expire);
        } catch (Exception e) {
        }
    }

    public void set(String k, float v) {
        try {
            db.putFloat(k, v);
            if (expire > 0)
                db.putLong(String.format(EXPIRE_KEY, k), System.currentTimeMillis() + expire);
        } catch (Exception e) {
        }
    }

    public void set(String k, double v) {
        try {
            db.putDouble(k, v);
            if (expire > 0)
                db.putLong(String.format(EXPIRE_KEY, k), System.currentTimeMillis() + expire);
        } catch (Exception e) {
        }
    }

    public void set(String k, String v) {
        try {
            db.put(k, v);
            if (expire > 0)
                db.putLong(String.format(EXPIRE_KEY, k), System.currentTimeMillis() + expire);
        } catch (Exception e) {
        }
    }

    public void set(String k, byte[] v) {
        try {
            db.put(k, v);
            if (expire > 0)
                db.putLong(String.format(EXPIRE_KEY, k), System.currentTimeMillis() + expire);
        } catch (Exception e) {
        }
    }

    public void set(String k, JSONObject v) {
        try {
            db.put(k, v.toString());
            if (expire > 0)
                db.putLong(String.format(EXPIRE_KEY, k), System.currentTimeMillis() + expire);
        } catch (Exception e) {
        }
    }

    public void set(String k, JSONArray v) {
        try {
            db.put(k, v.toString());
            if (expire > 0)
                db.putLong(String.format(EXPIRE_KEY, k), System.currentTimeMillis() + expire);
        } catch (Exception e) {
        }
    }

    @Override
    public void set(String k, Object v) {
        try {
            db.put(k, JSON.toJSONString(v));
            if (expire > 0)
                db.put(String.format(EXPIRE_KEY, k), System.currentTimeMillis() + expire);
        } catch (Exception e) {
        }
    }

    public void set(String k, boolean v, long ms) {
        try {
            db.putBoolean(k, v);
            db.putLong(String.format(EXPIRE_KEY, k), System.currentTimeMillis() + ms);
        } catch (Exception e) {
        }
    }

    public void set(String k, int v, long ms) {
        try {
            db.putInt(k, v);
            db.putLong(String.format(EXPIRE_KEY, k), System.currentTimeMillis() + ms);
        } catch (Exception e) {
        }
    }

    public void set(String k, long v, long ms) {
        try {
            db.putLong(k, v);
            db.putLong(String.format(EXPIRE_KEY, k), System.currentTimeMillis() + ms);
        } catch (Exception e) {
        }
    }

    public void set(String k, float v, long ms) {
        try {
            db.putFloat(k, v);
            db.putLong(String.format(EXPIRE_KEY, k), System.currentTimeMillis() + ms);
        } catch (Exception e) {
        }
    }

    public void set(String k, double v, long ms) {
        try {
            db.putDouble(k, v);
            db.putLong(String.format(EXPIRE_KEY, k), System.currentTimeMillis() + ms);
        } catch (Exception e) {
        }
    }

    public void set(String k, String v, long ms) {
        try {
            db.put(k, v);
            db.putLong(String.format(EXPIRE_KEY, k), System.currentTimeMillis() + ms);
        } catch (Exception e) {
        }
    }

    public void set(String k, byte[] v, long ms) {
        try {
            db.put(k, v);
            db.putLong(String.format(EXPIRE_KEY, k), System.currentTimeMillis() + ms);
        } catch (Exception e) {
        }
    }

    public void set(String k, JSONObject v, long ms) {
        try {
            db.put(k, v.toString());
            db.putLong(String.format(EXPIRE_KEY, k), System.currentTimeMillis() + ms);
        } catch (Exception e) {
        }
    }

    public void set(String k, JSONArray v, long ms) {
        try {
            db.put(k, v.toString());
            db.putLong(String.format(EXPIRE_KEY, k), System.currentTimeMillis() + ms);
        } catch (Exception e) {
        }
    }

    @Override
    public void set(String k, Object v, long ms) {
        try {
            db.put(k, JSON.toJSONString(v));
            db.put(String.format(EXPIRE_KEY, k), System.currentTimeMillis() + expire);
        } catch (Exception e) {
        }
    }

    private boolean isExpired(String k) {
        try {
            String ek = String.format(EXPIRE_KEY, k);
            if (db.exists(ek)) {
                long et = db.getLong(ek);
                return System.currentTimeMillis() > et;
            }
        } catch (Exception e) {
        }
        return false;
    }

    public boolean getBoolean(String k) {
        return getBoolean(k, false);
    }

    public int getInt(String k) {
        return getInt(k, 0);
    }

    public long getLong(String k) {
        return getLong(k, 0L);
    }

    public float getFloat(String k) {
        return getFloat(k, 0.0f);
    }

    public double getDouble(String k) {
        return getDouble(k, 0.0);
    }

    public byte[] getBytes(String k) {
        if (!isExpired(k)) {
            try {
                return db.getBytes(k);
            } catch (Exception e) {
            }
        }
        return null;
    }

    public String getString(String k) {
        return getString(k, null);
    }

    public JSONObject getJSONObject(String k) {
        if (!isExpired(k)) {
            try {
                String v = db.get(k);
                if (v != null && v.length() > 0) {
                    return (JSONObject) JSON.parse(v);
                }
            } catch (Exception e) {
            }
        }
        return null;
    }

    public JSONArray getJSONArray(String k) {
        if (!isExpired(k)) {
            try {
                String v = db.get(k);
                if (v != null && v.length() > 0) {
                    return (JSONArray) JSON.parse(v);
                }
            } catch (Exception e) {
            }
        }
        return null;
    }

    @Override
    public <T> T getObject(String k, Class<T> className) {
        if (!isExpired(k)) {
            try {
                String v = db.get(k);
                if (v != null && v.length() > 0) {
                    return JSON.parseObject(v, className);
                }
            } catch (Exception e) {
            }
        }
        return null;
    }

    public boolean getBoolean(String k, boolean v) {
        if (!isExpired(k)) {
            try {
                return db.getBoolean(k);
            } catch (Exception e) {
            }
        }
        return v;
    }

    public int getInt(String k, int v) {
        if (!isExpired(k)) {
            try {
                return db.getInt(k);
            } catch (Exception e) {
            }
        }
        return v;
    }

    public long getLong(String k, long v) {
        if (!isExpired(k)) {
            try {
                return db.getLong(k);
            } catch (Exception e) {
            }
        }
        return v;
    }

    public float getFloat(String k, float v) {
        if (!isExpired(k)) {
            try {
                return db.getFloat(k);
            } catch (Exception e) {
            }
        }
        return v;
    }

    public double getDouble(String k, double v) {
        if (!isExpired(k)) {
            try {
                return db.getDouble(k);
            } catch (Exception e) {
            }
        }
        return v;
    }

    public String getString(String k, String v) {
        if (!isExpired(k)) {
            try {
                return db.get(k);
            } catch (Exception e) {
            }
        }
        return v;
    }

}
